About Deferred Tasks
This information is from the Apple Technical Notes.
The Deferred Task Manager is useful for all lengthy interrupt time tasks, even those not initiated by slot cards. Deferring a task is useful any time
interrupt time code ( including completion routines, Time Manager tasks, etc.) is going to perform a lengthy task that can be accomplished with
interrupts enabled ( processor priority level 0).
The Deferred Task Manager is not available on the Mac Plus and Mac SE running System 6. There is also no support for it in versions of A/UX prior to
3.0. Macintosh System 7 added the Deferred Task Manager to the Mac Plus
and Mac SE.
You can check to make sure the Deferred Task Manager is available with
the following code that checks for the existence of the _DTInstall trap:
gHasDeferredTasks = TrapAvailable(_DTInstall);
DTQueue and JDTInstall are not available on the Mac Plus.
How and When the Deferred Task Manager calls deferred tasks
When an interrupt occurs, the processor stops executing the current
program, and control is passed to the Macintosh's primary interrupt handler.
The primary interrupt handler saves registers A0-A3/D0-D3 and then
decides what secondary interrupt handler to dispatch to. If the system has an
MMU, was booted in 24-bit mode but is presently in 32-bit mode, then the
MMU state is saved and the MMU is switched to 24-bit mode. If the system is a
portable and is in slow speed, the speed is saved and is then switched to full
speed. Control is then passed to the secondary interrupt handler which handles
the interrupt.
When control returns to the primary interrupt handler, it checks to see if
there are any deferred tasks in the deferred task queue and also checks to see if
upon exit of this interrupt, the processor priority level will be returned to 0.
If both conditions are true, control is passed to the Deferred Task Manager
to execute those tasks.
The Deferred Task Manager checks to see if a deferred task is already active; if so, it exits. Otherwise, one by one, each deferred task in the queue is
de queued, and then called with register A1 containing dtParm from the
DeferredTask record, and the processor priority level is set to 0 (i.e. all interrupts are enabled). When all deferred tasks have been de queued and
called, control is returned to the primary interrupt handler, which then
re stores the MMU state and speed if necessary and then re stores registers
A0-A3/D0-D3. Then it returns control to the program executing before the
interrupt occurred.
A deferred task must follow many of the same rules as an interrupt handler.
Warning: Deferred tasks are executed at the interrupt level
and must preserve all registers other than A0-A3 and D0-D3.
Your deferred task must not make any calls to the
on handles to unlocked blocks being valid. If it uses application
globals, it must also ensure that A5 contains the address of the
boundary between the application globals and the application
parameters. Your deferred task should avoid accessing a
low-memory variable or calling a trap that would access one
because while Multifinder or System 7 is running, application
low-memory global variables are being swapped in and out.
Some other important things to remember about deferred tasks:
• they must be interruptible
• they are executed in the order they were added to the queue, regardless of
the interrupt level the code installing the task was running at
• there may be significant latency between when a task is installed and
when it is executed
• when you install a deferred task, you give your DeferredTask record to the system, which owns it until the routine designated by the dtAddr field
of the DeferredTask record is entered. While the system owns the record, it may change it, and you may not.
Here is some sample code for obtaining the value of dtParm which is passed to
the deferred task in register A1:
pascal long GetDtParm (void) =
{ 0x2E89 }; /* MOVE.L A1,(SP) */
void DoDeferredTask (long dtParm);
void MyDeferredTask (void);
void DoDeferredTask(long dtParm)
{
/* your deferred task code goes here */
}
void MyDeferredTask (void)
{
long dtParm;
dtParm = GetDtParm(); /* get value of dtParm */
DoDeferredTask(dtParm); /* do deferred task */
}